home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 17442 < prev    next >
Encoding:
Text File  |  1996-08-05  |  7.2 KB  |  231 lines

  1. Path: news.belwue.de!uzwil!kuehl
  2. From: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Deriving class from IOSTREAMs
  5. Date: 16 Apr 1996 00:26:09 GMT
  6. Organization: FakultΣt fⁿr Mathematik und Informatik
  7. Message-ID: <4kupf1$720@news.BelWue.DE>
  8. References: <4ku9qa$7mt@bcarh8ab.bnr.ca>
  9. Reply-To: dietmar.kuehl@uni-konstanz.de
  10. NNTP-Posting-Host: uzwil.informatik.uni-konstanz.de
  11. X-Newsreader: TIN [version 1.2 PL2]
  12.  
  13. Hi,
  14.  
  15. Jim Cobban (jcobban@bnr.ca) wrote:
  16. : I am trying to define a class which has the following characteristics:
  17.  
  18. :   1) It supports the insertion (<<) operator of the ostream class.
  19. :   2) Output is organized into units of work.  No part of a unit of work
  20. :      can be written to the output device until the unit of work is complete.
  21. :      Then all of the text in the unit of work must be placed on the same line
  22. :      of output.  In other words if there is enough room on the current line
  23. :      to hold all of the text then it will be printed on the current line,
  24. :      otherwise a new line is started and the text is written on the new line.
  25. :   3) When a new line is started, including the very first line in the output,
  26. :      an application specified prefix is written before the first unit of
  27. :      work.
  28.  
  29. : The first requirement dictates that my class be derived directly or
  30. : indirectly from ostream.
  31.  
  32. This is already the problem! You are not supposed to derive from
  33. 'ostream'. 'ostream' is not intended to be used as a base class except
  34. for creational purposes! If you want to create a new "external
  35. representation" you should derive from 'streambuf'. You can than use
  36. the specialized 'streambuf' to instantiate an 'ostream' (or create a
  37. class derived from 'ostream' which does so automatically; this is the
  38. only reason to derive from 'ostream').
  39.  
  40. : The second requirement seems to me to dictate that
  41. : my class be derived, in particular, from ostrstream, which provides a buffer
  42. : in which output can be held until a unit of work is complete.
  43.  
  44. The buffer management is basically implemented by 'streambuf' so you
  45. don't need to use 'ostrstream' (it's use is deprecated anyway; it is
  46. superseeded by 'ostringstream' which is unfortunately not yet part of
  47. all libraries shipped with the compilers).
  48.  
  49. : I would like
  50. : the end of a unit of work to be signalled by a manipulator, but I have had a
  51. : great deal of difficulty in getting that to work.
  52.  
  53. This becomes quite easy with the approach I mentioned above. I won't
  54. discuss your approach, as it is not the way to go anyway. Instead you
  55. should do something like done by the code I have appended to this
  56. article (this is probably not the exact behavior you want because I
  57. haven't completely understood what you want to do to the lines...).
  58. Note, that the code below is not tested very well: I have just tested
  59. that it performs some basic stuff. It is likely that there are quite a
  60. few bugs.  Also, there are only very few comments. For more documented
  61. examples, have a look at
  62. <http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream>: This page
  63. references two other examples of new "external representations", namely
  64. a 'wstream' writing to a GUI window (in this case a Motif 'TextWidget')
  65. and a 'prfxstream' writing and reading lines with a prefix.
  66. --
  67. dietmar.kuehl@uni-konstanz.de
  68. http://www.informatik.uni-konstanz.de/~kuehl/
  69. I am a realistic optimist - that's why I appear to be slightly pessimistic
  70.  
  71. // <!!-*-C++-*- file: workstream.cc --->
  72. // <!!------------------------------------------------------------------------->
  73. // <!! Copyright (C) 1996 Dietmar Kuehl >
  74. // <!!   Universitaet Konstanz, Lehrstuhl fuer praktische Informatik I >
  75. // <!!>
  76. // <!! This file is free software; you can redistribute it and/or modify >
  77. // <!! it under the terms of the GNU General Public License as published by >
  78. // <!! the Free Software Foundation; either version 2 of the License, or >
  79. // <!! (at your option) any later version. >
  80. // <!!>
  81. // <!! This program is distributed in the hope that it will be useful, >
  82. // <!! but WITHOUT ANY WARRANTY; without even the implied warranty of >
  83. // <!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the >
  84. // <!! GNU General Public License for more details. >
  85. // <!!------------------------------------------------------------------------->
  86.  
  87. // Author: Dietmar Kⁿhl dietmar.kuehl@uni-konstanz.de www.informatik.uni-konstanz.de/~kuehl
  88. // Title:  A stream writing when the manipulator 'endw' is applied.
  89.  
  90. //------------------------------------------------------------------------------
  91.  
  92. #include <iostream.h>
  93. #include <cstring>
  94.  
  95. class workbuf: public streambuf
  96. {
  97. private:
  98.   static const int buf_size = 1024;
  99.  
  100.   streambuf  *sbuf;   // the actual external representation
  101.   char const *prefix; // the line to be written as a prefix
  102.  
  103.   workbuf(workbuf const &);
  104.   workbuf operator= (workbuf const &);
  105.  
  106.   void increase_buffer(int add_size = buf_size); // increases the buffer
  107.   void write_buffer();    // write the buffer to the actual representation
  108.  
  109. public:
  110.   workbuf(char const *prfx, streambuf *sb);
  111.   ~workbuf();
  112.  
  113.   int overflow(int c);
  114.   int xsputn(const char *s, int n);
  115.  
  116.   virtual void end_work(); // called by the manipulator 'endw'
  117. };
  118.  
  119. workbuf::workbuf(char const *prfx, streambuf *sb):
  120.   sbuf(sb),
  121.   prefix(strcpy(new char[strlen(prfx) + 1], prfx))
  122. {
  123.   char *buffer = new char[buf_size];
  124.   setp(buffer, buffer + buf_size);
  125. }
  126.  
  127. workbuf::~workbuf()
  128. {
  129.   if (pbase() != epptr())
  130.     write_buffer();
  131.   delete[] pbase();
  132.   setp(0, 0);
  133.   delete[] prefix;
  134. }
  135.  
  136. void workbuf::increase_buffer(int add_size)
  137. {
  138.   int size = epptr() - pbase();
  139.   char *new_buf = new char[size + add_size];
  140.   memcpy(new_buf, pbase(), size);
  141.   delete[] pbase();
  142.   setp(new_buf, new_buf + size + add_size);
  143.   pbump(size);
  144. }
  145.  
  146. void workbuf::write_buffer()
  147. {
  148.   sbuf->sputn(prefix, strlen(prefix));
  149.   sbuf->sputn(pbase(), pptr() - pbase());
  150.   sbuf->sputc('\n');
  151.   sbuf->sync();
  152.  
  153.   setp(pbase(), epptr());
  154. }
  155.  
  156. int workbuf::overflow(int c)
  157. {
  158.   increase_buffer();
  159.   return sputc(c);
  160. }
  161.  
  162. int workbuf::xsputn(const char *s, int n)
  163. {
  164.   int left = epptr() - pptr();
  165.   if (left < n)
  166.     increase_buffer(n - left > buf_size? n - left + buf_size: buf_size);
  167.   memcpy(pptr(), s, n);
  168.   pbump(n);
  169.   return n;
  170. }
  171.  
  172. void workbuf::end_work()
  173. {
  174.   write_buffer();
  175. }
  176.  
  177. //------------------------------------------------------------------------------
  178.  
  179. class oworkstream: public ostream
  180. {
  181.   friend ostream &endw(ostream &);
  182.  
  183. private:
  184.   static int data_idx;
  185.  
  186.   streambuf *sbuf;
  187.  
  188.   oworkstream(oworkstream const &);
  189.   oworkstream &operator=(oworkstream const &);
  190. public:
  191.   oworkstream(char const *prefix, streambuf *sb);
  192.   ~oworkstream();
  193. };
  194.  
  195. int oworkstream::data_idx = ios::xalloc();
  196.  
  197. oworkstream::oworkstream(char const *prefix, streambuf *sb):
  198.   ostream(new workbuf(prefix, sb)),
  199.   sbuf(rdbuf())
  200. {
  201.   pword(data_idx) = rdbuf();
  202. }
  203.  
  204. oworkstream::~oworkstream()
  205. {
  206.   delete sbuf;
  207. }
  208.  
  209. ostream &endw(ostream &out)
  210. {
  211.   if (out.pword(oworkstream::data_idx) == out.rdbuf())
  212.   {
  213.     workbuf *wb = (workbuf *)out.rdbuf();
  214.     wb->end_work();
  215.   }
  216.   else
  217.     cerr << "'endw' manipulator applied to non-'oworkstream'!\n";
  218.   return out;
  219. }
  220.  
  221. //------------------------------------------------------------------------------
  222.  
  223. int main()
  224. {
  225.   oworkstream out("prefix: ", cout.rdbuf());
  226.  
  227.   out << "hello world" << endw;
  228.   out << "goodbye";
  229.   return 0;
  230. }
  231.